package com.example.socket;

import com.example.constant.sta;
import com.example.info.DeviceInfo;
import com.example.mapper.DeviceDataMapper;
import com.example.mapper.MachineMapper;
import com.example.mapper.SampleMapper;
import com.example.pojo.VerifyResult;
import com.example.service.VerifyService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Component
public class SocketServer {
    // 存储所有设备连接的映射: machineID -> ClientHandler
    private final ConcurrentHashMap<Integer, ClientHandler> clientHandlers = new ConcurrentHashMap<>();
    // 存储所有活动连接的映射: Socket -> machineID
    private final ConcurrentHashMap<Socket, Integer> socketMachineMap = new ConcurrentHashMap<>();

    @Autowired
    private DeviceDataMapper deviceDataMapper;
    @Autowired
    private SampleMapper sampleMapper;
    @Autowired
    private MachineMapper machineMapper;
    @Autowired
    private VerifyService verifyService;

    // 定时任务调度线程池，核心线程数固定为10（即使空闲也保留），用于执行延迟任务和周期性任务，与链接设备数无关
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);

    // 1 个监听线程 + N 个处理线程（N = 同时连接的设备数）
    @PostConstruct
    public void startSocketServer() {
        new Thread(() -> {
            try (ServerSocket serverSocket = new ServerSocket(8880)) {
                System.out.println("Socket 服务端启动，等待客户端连接...");

                while (true) {
                    try {
                        Socket socket = serverSocket.accept();
                        System.out.println("客户端已连接：" + socket.getInetAddress());

                        // 创建新的客户端处理器
                        ClientHandler clientHandler = new ClientHandler(socket);
                        new Thread(clientHandler).start();

                    } catch (IOException e) {
                        System.out.println("接收客户端连接时异常：" + e.getMessage());
                    }
                }
            } catch (IOException e) {
                System.out.println("Socket 服务端启动失败：" + e.getMessage());
            }
        }).start();
    }

    @PreDestroy
    public void cleanup() {
        scheduler.shutdownNow();
        // 关闭所有连接
        clientHandlers.values().forEach(ClientHandler::closeConnection);
    }

    public Socket getClientSocket(int machineId) {
        ClientHandler handler = clientHandlers.get(machineId);
        return (handler != null && handler.isActive()) ? handler.getSocket() : null;
    }

    public void startVerifyTimeout(int machineId) {
        ClientHandler handler = clientHandlers.get(machineId);
        if (handler != null) {
            handler.startVerifyTimeout();
        }
    }

    // 内部类：每个设备一个处理器
    private class ClientHandler implements Runnable {

        // 存储当前客户端连接的 Socket 对象
        private final Socket socket;

        // 线程安全的连接状态标识
        private final AtomicBoolean active = new AtomicBoolean(true);

        // 记录最后一次发起验证请求的时间戳
        private volatile long lastVerifyRequestTime = 0;

        // 标记是否收到验证响应
        private volatile boolean verifyResponseReceived = false;

        // 存储当前连接对应的设备ID
        private volatile int machineId = -1;

        // 控制超时检测任务的句柄
        private ScheduledFuture<?> timeoutTask;

        public ClientHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))) {

                while (active.get()) {
                    // 读取10字节的长度前缀
                    StringBuilder lengthBuilder = new StringBuilder();
                    int totalCharsRead = 0;

                    // 累积读取10字节，跳过可能的换行符
                    while (totalCharsRead < 10) {
                        int ch = reader.read();
                        if (ch == -1) {
                            log.info("客户端 {} 连接断开", socket.getInetAddress());
                            return; // 客户端关闭连接
                        }
                        char c = (char) ch;
                        // 跳过换行符或回车符
                        if (c == '\n' || c == '\r') {
                            continue;
                        }
                        lengthBuilder.append(c);
                        totalCharsRead++;
                    }

                    // 确保读取到10字节
                    if (lengthBuilder.length() != 10) {
                        log.error("读取长度前缀失败，期望10字节，实际读取 {} 字节", lengthBuilder.length());
                        continue;
                    }

                    // 解析长度
                    String lengthStr = lengthBuilder.toString().trim();
                    int jsonLength;
                    try {
                        jsonLength = Integer.parseInt(lengthStr);
                    } catch (NumberFormatException e) {
                        log.error("无效的长度前缀: {}", lengthStr);
                        continue;
                    }

                    // 读取JSON数据
                    char[] jsonBuffer = new char[jsonLength];
                    int charsRead = 0;
                    while (charsRead < jsonLength) {
                        int read = reader.read(jsonBuffer, charsRead, jsonLength - charsRead);
                        if (read == -1) {
                            log.info("客户端 {} 连接断开", socket.getInetAddress());
                            return;
                        }
                        charsRead += read;
                    }

                    String jsonData = new String(jsonBuffer);
                    log.info("Received from {}: {}", socket.getInetAddress(), jsonData);

                    try {
                        // 尝试解析为验证结果
                        VerifyResult verifyResult = new ObjectMapper().readValue(jsonData, VerifyResult.class);
                        handleVerifyResult(verifyResult);
                    } catch (IOException e1) {
                        try {
                            // 尝试解析为设备信息
                            DeviceInfo deviceInfo = new ObjectMapper().readValue(jsonData, DeviceInfo.class);
                            handleDeviceInfo(deviceInfo);
                        } catch (IOException e2) {
                            log.error("无法解析的消息: {}", jsonData);
                        }
                    }
                }
            } catch (IOException e) {
                log.info("接收异常：" + e.getMessage());
            }
            // 不自动关闭连接，仅在超时任务中关闭
        }

        private void handleVerifyResult(VerifyResult verifyResult) {
            log.info("设备 {} 返回的结果信息:{}", machineId, verifyResult);

            verifyResponseReceived = true;

            if (timeoutTask != null) {
                timeoutTask.cancel(false);
                timeoutTask = null;
            }

            List<String> BN = new ArrayList<>();
            List<String> DN = new ArrayList<>();
            List<Integer> BID = new ArrayList<>();
            List<Integer> DID = new ArrayList<>();

            for (String filename : verifyResult.getFileList()) {
                Integer brandID = sampleMapper.getBrandID(filename);
                if (brandID == null) {
                    log.warn("未找到文件对应的品牌ID: {}", filename);
                    BID.add(null);
                    BN.add("未知品牌");
                } else {
                    String brandName = sampleMapper.getBrandName(brandID);
                    BN.add(brandName != null ? brandName : "未知品牌");
                    BID.add(brandID);
                }

                Integer defectID = sampleMapper.getDefectID(filename);
                if (defectID == null) {
                    log.warn("未找到文件对应的缺陷ID: {}", filename);
                    DID.add(null);
                    DN.add("未知缺陷");
                } else {
                    String defectName = sampleMapper.getDefectName(defectID);
                    DN.add(defectName != null ? defectName : "未知缺陷");
                    DID.add(defectID);
                }
            }

            verifyResult.setBrandName(BN);
            verifyResult.setDefectName(DN);
            verifyResult.setBrandID(BID);
            verifyResult.setDefectID(DID);
            verifyResult.setMachineID(machineMapper.getMachineIDById(machineId));

            log.info("拼接后的结果信息:{}", verifyResult);
            verifyService.completeVerifyResult(verifyResult);
        }

        private void handleDeviceInfo(DeviceInfo deviceInfo) {
            this.machineId = machineMapper.getIdByMachineID(deviceInfo.getMachineID());
            log.info("新增设备信息: {}, machineID: {}", deviceInfo, machineId);

            // 添加到设备映射
            clientHandlers.put(machineId, this);
            socketMachineMap.put(socket, machineId);

            // 更新设备状态
            updateMachineStatus(1, machineId);
            deviceDataMapper.save(deviceInfo);
        }

        public void startVerifyTimeout() {
            verifyResponseReceived = false;

            lastVerifyRequestTime = System.currentTimeMillis();

            if (timeoutTask != null) {
                timeoutTask.cancel(false);
            }

            timeoutTask = scheduler.schedule(() -> {
                if (!verifyResponseReceived) {
                    log.warn("设备 {} 验证超时，关闭连接", machineId);
                    closeConnection();
                }
            }, 1, TimeUnit.MINUTES);
        }

        public void closeConnection() {
            if (active.compareAndSet(true, false)) {
                try {
                    if (socket != null && !socket.isClosed()) {
                        socket.close();
                    }

                    if (machineId != -1) {
                        updateMachineStatus(0, machineId);
                        clientHandlers.remove(machineId);
                    }
                    socketMachineMap.remove(socket);

                    log.info("设备 {} 连接已关闭", machineId);
                } catch (IOException e) {
                    log.error("关闭连接时出错", e);
                }
            }
        }

        public boolean isActive() {
            return active.get();
        }

        public Socket getSocket() {
            return socket;
        }
    }

    private void updateMachineStatus(int status, int machineId) {
        machineMapper.updateIsConnected(status, machineId);
    }
}
